package com.jiantong.web.core.component.user.service.impl;

import com.google.common.base.Throwables;
import com.jiantong.web.core.component.user.service.UserDeviceService;
import io.terminus.common.model.Response;
import io.terminus.common.redis.utils.JedisTemplate;
import io.terminus.msg.api.app.UserDeviceReadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * redis实现
 *
 * DATE: 17/1/12 下午2:33 <br>
 * MAIL: zhanghecheng@terminus.io <br>
 * AUTHOR: zhanghecheng
 */
@ConditionalOnClass(UserDeviceReadService.class)
@Component
@Slf4j
public class DefaultUserDeviceServiceImpl implements UserDeviceReadService, UserDeviceService {

    @Autowired(required = false)
    protected JedisTemplate jedisTemplate;

    @Value("${session.app.expire.interval:259200}") //3days
    protected Integer sessionAppExpireInterval;


    protected String userDeviceKey(Long userId, String deviceType, String deviceToken){
        return String.format("user:%d:%s:%s", userId, deviceType, deviceToken);
    }

    protected String userDeviceKeyPattern(Long userId, String deviceType){
        return String.format("user:%d:%s:*", userId, deviceType);
    }

    protected String deviceUserKeyPattern(String deviceType, String deviceToken){
        return String.format("user:*:%s:%s", deviceType, deviceToken);
    }


    @Override
    public Response<Boolean> addDevice(Long userId, String deviceType, String deviceToken) {
        try {
            if(jedisTemplate==null){
                log.error("addDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                        userId, deviceType, deviceToken, "jedis.template.bean.missing");
                return Response.fail("jedis.template.bean.missing");
            }

            /*
             * 找出该设备号是否对应有登录的用户, 如果有则剔除
             */
            Set<String> users = jedisTemplate.execute(jedis -> {
                return jedis.keys(deviceUserKeyPattern(deviceType, deviceToken));
            });
            if(!users.isEmpty()) {
                jedisTemplate.execute(jedis -> {
                    jedis.del(users.toArray(new String[0]));
                });
            }

            Boolean result = jedisTemplate.execute(jedis -> {
                jedis.setex(userDeviceKey(userId, deviceType, deviceToken), sessionAppExpireInterval, deviceToken);
                return true;
            });
            return Response.ok(result);
        }catch (Exception e){
            log.error("addDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                    userId, deviceType, deviceToken, Throwables.getStackTraceAsString(e));
            return Response.fail("device.add.fail");
        }
    }

    @Override
    public Response<Boolean> removeDevice(Long userId, String deviceType, String deviceToken) {
        try{
            if(jedisTemplate==null){
                log.error("addDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                        userId, deviceType, deviceToken, "jedis.template.bean.missing");
                return Response.fail("jedis.template.bean.missing");
            }
            Boolean result = jedisTemplate.execute(jedis -> {
                jedis.del(userDeviceKey(userId, deviceType, deviceToken));
                return Boolean.TRUE;
            });
            return Response.ok(result);
        }catch (Exception e){
            log.error("removeDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                    userId, deviceType, deviceToken, Throwables.getStackTraceAsString(e));
            return Response.fail("device.remove.fail");
        }
    }

    @Override
    public Set<String> findDevices(Long userId, String deviceType){
        try{
            if(jedisTemplate==null){
                log.error("addDevice fail, userId={}, deviceType={}, cause={}",
                        userId, deviceType, "jedis.template.bean.missing");
                return Collections.emptySet();
            }
            Set<String> keys = jedisTemplate.execute(jedis -> {
                return jedis.keys(userDeviceKeyPattern(userId, deviceType));
            });
            if(keys.isEmpty()){
                return Collections.emptySet();
            }
            List<String> values = jedisTemplate.execute(jedis -> {
                return jedis.mget(keys.toArray(new String[0]));
            });
            return new HashSet<>(values);

        }catch (Exception e){
            log.error("findDevices fail, userId={}, deviceType={}, cause={}",
                    userId, deviceType, Throwables.getStackTraceAsString(e));
            return Collections.emptySet();
        }
    }

    @Override
    public Response<Boolean> refresh(Long userId, String deviceType, String deviceToken) {
        try {
            if(jedisTemplate==null){
                log.error("addDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                        userId, deviceType, deviceToken, "jedis.template.bean.missing");
                return Response.fail("jedis.template.bean.missing");
            }
            Boolean result = jedisTemplate.execute(jedis -> {
                jedis.expire(userDeviceKey(userId, deviceType, deviceToken), sessionAppExpireInterval);
                return true;
            });
            return Response.ok(result);
        }catch (Exception e){
            log.error("addDevice fail, userId={}, deviceType={}, deviceToken={}, cause={}",
                    userId, deviceType, deviceToken, Throwables.getStackTraceAsString(e));
            return Response.fail("device.add.fail");
        }
    }
}
